from typing import Dict, Union
import json

import requests
from requests.models import Response
import lxml.html
from lxml import etree
from lxml.html import HtmlElement
from fake_useragent import UserAgent


LINK_TO_PAGE = 'https://hh.ru/search/vacancy?area=53&enable_snippets=true&ored_clusters=true&text=python&order_by=publication_time&hhtmFrom=vacancy_search_list'


def get_page_content(link_to_page) -> HtmlElement:
    """ Получаем содержимое страницы """

    def check_status_of_response_code(response: Response) -> None:
        """ Проверяем статус код ответа """

        status_response_code = response.status_code
        if status_response_code != 200:
            message = f'[*] STATUS CODE - {status_response_code}'
            raise ValueError(message)

    def send_request() -> HtmlElement:
        """ Отправляем запрос на получение нужной страницы """


        ua = UserAgent()
        headers = {'User-Agent': ua.chrome}
        response = requests.get(link_to_page, headers=headers)
        check_status_of_response_code(response)
        tree = lxml.html.document_fromstring(response.text)
        return tree


    # ВЫШЕ ОПРЕДЕЛЕНИЕ ФУНКЦИЙ

    response = send_request()
    return response


def get_all_vacancies() -> Dict[str, str]:
    """ Получаем все вакансии """

    def select_all_vacancies(page_content: HtmlElement) -> Dict[str, str]:
        """ Выбираем все вакансии со страницы """

        result = {}
        all_vacancies = page_content.xpath('//a[@class="serp-item__title"]')

        for count, vacancies in enumerate(all_vacancies):
            title = vacancies.text_content()
            link = vacancies.get('href')
            result[count] = {'title': title, 'link': link}

        return result


    # ВЫШЕ ОПРЕДЕЛЕНИЕ ФУНКЦИЙ

    page_content = get_page_content(LINK_TO_PAGE)
    all_vacancies = select_all_vacancies(page_content)
    return all_vacancies


def get_all_vacancies_from_general_list() -> Dict[str, str]:
    """ Получаем все вакансии из общего списка """

    with open('general_list_of_vacancies.json') as file:
        data = json.load(file)
        return data


def add_new_vacancies_to_general_list(all_vacancies_from_general_list,
                                      vacancies: Dict[int, Dict[str, str]]) -> None:
    """ Добавляем новые вакансии в общий список """

    try:
        initial_key = max(
            map(int, all_vacancies_from_general_list.keys())
        ) + 1
    except ValueError:
        initial_key = 0

    for vacancy in vacancies.values():
        all_vacancies_from_general_list[initial_key] = vacancy
        initial_key += 1

    data = json.dumps(all_vacancies_from_general_list)

    with open('general_list_of_vacancies.json', 'w') as file:
        file.write(data)


def compare_vacancies(general_list_of_vacancies: Dict[str, str],
                      vacancies_received: Dict[str, str]):
    """ Сравниваем вакансии, получая новые """

    new_vacancies = {}

    for count, vacancies in enumerate(vacancies_received.values()):
        if not vacancies in general_list_of_vacancies.values():
            new_vacancies[count] = vacancies

    return new_vacancies


def get_new_vacancies(all_vacancies_from_general_list: Union[Dict, Dict[int, Dict[str, str]]]) -> Dict[int, Dict[str, str]]:
    """ Получаем новые вакансии """

    vacancies_received = get_all_vacancies()
    new_vacancies = compare_vacancies(all_vacancies_from_general_list, vacancies_received)
    return new_vacancies


def show_new_vacancies(vacancies: Dict[int, Dict[str, str]]) -> None:
    """ Показываем новые вакансии """

    if not vacancies:
        print('\n[*] No new vacancies found\n')

    for vacancy in vacancies.values():
        message = f'[*] {vacancy["title"]} {vacancy["link"]}'
        print(message)


def main():
    all_vacancies_from_general_list = get_all_vacancies_from_general_list()
    new_vacancies = get_new_vacancies(all_vacancies_from_general_list)
    add_new_vacancies_to_general_list(all_vacancies_from_general_list, new_vacancies)
    show_new_vacancies(new_vacancies)


if __name__ == '__main__':
    main()
